package com.ebs.md.impl.payload.order;

/**
 * Perforce Revision:
 *  $File: //depot/MarketData/commons-md-payload-impl/MAIN/src/main/java/com/ebs/md/impl/payload/order/OrderAdapterImpl.java $
 *  $Revision: #5 $  $Change: 115126 $  $DateTime: 2012/09/23 15:15:49 $  $Author: Aviad.Yosef $
 */

import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;
import java.util.TimeZone;

import org.apache.log4j.Logger;

import com.ebs.commons.comp.IParsedPayload;
import com.ebs.core.CoreEx;
import com.ebs.md.api.IIdentifiedOrder;
import com.ebs.md.api.OrderOperation;
import com.ebs.md.api.OrderSide;
import com.ebs.md.api.Rate;
import com.ebs.md.api.abs.AbsProductProvider;
import com.ebs.md.api.abs.BasicIdentifiedOrder;
import com.ebs.md.api.order.IOrderAdapter;
import com.ebs.md.api.product.PairProduct;

/**
 * 
 *
 * @see com.ebs.tdl.input.jarb.PayloadCreator
 * @see message_conversion_properties.xml
 */
public class OrderAdapterImpl
implements IOrderAdapter<IParsedPayload, IIdentifiedOrder>
{
    protected final Logger  logger = Logger.getLogger(getClass());

	final static String PAYLOAD_FIELD_NAME_QTE_AMOUNT_AVAIL  =  "qte_amt_avail_result";
	final static String PAYLOAD_FIELD_NAME_QTE_AMOUNT        =  "qte_amt_result";
	final static String PAYLOAD_FIELD_NAME_QTE_AMOUNT_DISPLAY=  "qte_amt_display_result";
	final static String PAYLOAD_FIELD_NAME_REGION            =  "trader_region";
	
	static protected final Set<String> QTE_AVAIL_NAMES;
	
	static {
		QTE_AVAIL_NAMES = new HashSet<String>(5);
		QTE_AVAIL_NAMES.add("RQTM");
	}
	
	protected AbsProductProvider<String, PairProduct> pairProductProvider;
	
	public void setPairProductProvider(AbsProductProvider<String, PairProduct> pairProductProvider) {
		this.pairProductProvider = pairProductProvider;
	}


	public IIdentifiedOrder convert(IParsedPayload source) {
		OrderOperation operation = decideOperation(source);
		
		if ( operation == null ) {
			return null;
		}
		PairProduct product = extractProduct(source);
		OrderSide   side    = extractSide(source);
		long        amount  = extractAmount(source);
		String      region  = extractRegion(source);
		Rate        rate    = null;
		long        totalAmount = amount;
		long        displayAmount = amount;
		
		switch(operation) {
		case ADD:
			rate = extractRate(source);
			totalAmount = extractTotalAmount(source);
			displayAmount = extractDisplayAmount(source);
			break;
		case REMOVE:
		case CANCEL:
			// do nothing
			break;
		case INCREASE_AMOUNT:
		case DECREASE_AMOUNT:
			amount = Math.abs(amount);
			break;
		default:
			logger.warn("does not support such operation : " + operation);
			return null;
		}
		
		BasicIdentifiedOrder bio = new BasicIdentifiedOrder(product, amount, side, operation, rate, totalAmount, displayAmount, region);
		
		addIdentifications(bio, source);
		
		return bio;
	}

	
	protected OrderSide extractSide(IParsedPayload pp) {
		return OrderSide.byLegcayCode(pp.getParsedIntField("qte_type"));
	}

	protected Rate extractRate(IParsedPayload pp) {
		return new Rate(pp.getParsedStringField("prc_qte_value", "0.0"));
	}
	
	protected long extractAmount(IParsedPayload pp) {
		String amtPayloadName;
		String mqMsgType = pp.getParsedStringField("mq_msg_type");
		if ( QTE_AVAIL_NAMES.contains(mqMsgType) ) {
			amtPayloadName = PAYLOAD_FIELD_NAME_QTE_AMOUNT_AVAIL; 
		} else {
			amtPayloadName = PAYLOAD_FIELD_NAME_QTE_AMOUNT;
		}
		
		return pp.getParsedLongField(amtPayloadName, 0);
	}

	protected String extractRegion(IParsedPayload pp) {
		return pp.getParsedStringField(PAYLOAD_FIELD_NAME_REGION);
	}
	
	protected long extractTotalAmount(IParsedPayload pp) {
		return pp.getParsedLongField(PAYLOAD_FIELD_NAME_QTE_AMOUNT, 0);
	}
	
	protected long extractDisplayAmount(IParsedPayload pp) {
		return pp.getParsedLongField(PAYLOAD_FIELD_NAME_QTE_AMOUNT_DISPLAY, 0);
	}
	
	protected PairProduct extractProduct(IParsedPayload pp) {
		String  baseCcyIso  = pp.getParsedStringField ( "base_ccy");
		String localCcyIso  = pp.getParsedStringField ("local_ccy");
		int    matchingType = pp.getParsedIntField    ("matching_type");
		
		String productKey = PairProduct.generateKey(baseCcyIso, localCcyIso, matchingType);
		
		PairProduct cachedProduct = pairProductProvider.getProduct(productKey);
		
		if ( cachedProduct == null ) {
			// caching it
			cachedProduct = new PairProduct(baseCcyIso, localCcyIso, matchingType);
			
			pairProductProvider.storeKnownItem(productKey, cachedProduct);
		}
		return cachedProduct;
		
	}

	static final protected TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
	
	protected void addIdentifications(BasicIdentifiedOrder bio, IParsedPayload pp) {
		String quoteId  = pp.getParsedStringField("ebs_trans_id");
		String dealCode = pp.getParsedStringField("qte_floor_code");
		String traderId = pp.getParsedStringField("trader_id");
		long   msgTime  = pp.getParsedLongField("msg_timestamp_long", 0);
		
		Calendar quoteTime = Calendar.getInstance(gmtTZ);
		quoteTime.setTimeInMillis(msgTime);
		
		bio.setIdentifiers(quoteId, quoteTime, dealCode, traderId);
	}

	protected OrderOperation decideOperation(IParsedPayload source) {
		OrderOperation operation = null;
		String mqMsgType = source.getParsedStringField("mq_msg_type");
		// RQTM = AD_MKTQTEAVAILABLE
		if ( "RQTM".equals(mqMsgType) ) {
			operation = OrderOperation.ADD;
		}
		// RQTN = AD_MKTQTEDONE
		if ( "RQTN".equals(mqMsgType) ) {
			operation = OrderOperation.REMOVE;
		}
		// RMQI = AD_MKTQTEINTERRUPTED
		if ( "RMQI".equals(mqMsgType) ) {
			operation = OrderOperation.CANCEL;
		}
		// RQTU = AD_MKTQTEAMTUNRESERVED
		if ( "RQTU".equals(mqMsgType) ) {
			operation = OrderOperation.INCREASE_AMOUNT;
		}
		// RQTR = AD_MKTQTEAMTRESERVED
		if ( "RQTR".equals(mqMsgType) ) {
			operation = OrderOperation.DECREASE_AMOUNT;
		}
		// RMAD = AD_MKTQTEAMENDED
		if ( "RMAD".equals(mqMsgType) ) {
			int amendType = source.getParsedIntField("amend_type");
			
			switch(amendType) {
			case CoreEx.CODE_MktQteAmendType_REDUCE:
				operation = OrderOperation.DECREASE_AMOUNT;
				break;
			default:  
//			case CoreEx.CODE_MktQteAmendType_PD:
//			case CoreEx.CODE_MktQteAmendType_GENERICDETAILS:
				long amount = source.getParsedLongField("qte_amt_result", 0);
				
				if ( amount > 0 ) {
					operation = OrderOperation.INCREASE_AMOUNT;
				}
				if ( amount < 0 ) {
					operation = OrderOperation.DECREASE_AMOUNT;
				}
				
			}
			
		}
		return operation;
	}
	
}
